#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <functional>
#include <cstdlib>
#include <cstring>
#include<unistd.h>
#include<unordered_map>
#include "lockGuard.hpp"
#include "RingQueue.hpp"
#include "thread.hpp"
#include "error.hpp"
namespace Server_UDP
{
    static const uint16_t default_port = 8080;

    class server
    {
    public:
        server(uint16_t port = default_port) : _port(port)
        {
            _p = new thread(1, std::bind(&server::recv, this), nullptr);
            _c = new thread(2, std::bind(&server::broadcast, this), nullptr);
            pthread_mutex_init(&_lock, nullptr);
        }
        void start()
        {
            // SOCK_STREAM  -----TCP      SOCK_DGRAM ------UDP
            _sock = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sock < 0)
            {
                std::cerr << "create socket error: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }
            // create success

            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            // AF_INET -----IPV4   AF_INET6------IPV6
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            // 云服务器一般不知名某一个确定的地址，INADDR_ANY可以让udpserver在启动的时候绑定本主机的任意ip
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                std::cerr << "bind socket error: " << strerror(errno) << std::endl;
                exit(BIND_ERR);
            }
            // 绑定成功
            std::cout<<"bind success: "<<_sock<<std::endl;
            _p->run();
            _c->run();
        }
        void recv()
        {
            char buffer[1024];
            while (true)
            {
                // 接受消息

                // 存储发送方的ip和port地址
                struct sockaddr_in peer;
                //存储信息结构体的大小
                socklen_t len = sizeof(peer);
                ssize_t n = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
                if(n>0)
                {
                    buffer[n]='\0';
                }
                else
                {
                    continue;
                }
                std::cout<<"recv done ..."<<std::endl;
                //提取client信息
                std::string clientIP=inet_ntoa(peer.sin_addr);
                uint16_t clientPort=ntohs(peer.sin_port);
                std::cout << clientIP << "-" << clientPort << "# " << buffer << std::endl;
                //构建用户
                std::string name=clientIP+"-"+std::to_string(clientPort);
                addUser(name,peer);
                std::string message=name+buffer;
                _rq.push(message);
            }
        }
        void broadcast()
        {
            //将接受到的数据广播
            while(true)
            {
                std::string sendMessage;
                _rq.pop(sendMessage);

                std::vector<struct sockaddr_in> v;


                {
                    xjc::lockGuard guard(&_lock);
                    for(auto user:_onlineUser)
                    {
                        v.push_back(user.second);
                    }
                }
                for(auto user:v)
                {
                    //对所有用户广播信息
                    sendto(_sock,sendMessage.c_str(),sendMessage.size(),0,(struct sockaddr*)&(user),sizeof(user));
                    std::cout<<"send to done..."<<std::endl;
                }
                
            }
        }
        void addUser(const std::string& name,const struct sockaddr_in& peer)
        {
            xjc::lockGuard guard(&_lock);
            auto iter = _onlineUser.find(name);
            if(iter!=_onlineUser.end())
            {
                //找到了这个user
                return;
            }
            _onlineUser.insert(std::pair<const std::string,const struct sockaddr_in>(name,peer));
        }
        ~server()
        {
            pthread_mutex_destroy(&_lock);
            _p->join();
            _c->join();
            delete _p;
            delete _c;
            close(_sock);
        }

    private:
        int _sock;
        uint16_t _port;
        RingQueue<std::string> _rq; // 消息队列
        pthread_mutex_t _lock;
        std::unordered_map<std::string,struct sockaddr_in> _onlineUser;
        thread *_p;
        thread *_c;
    };
}